/*
 * =====================================================================================
 *
 *       Filename:  ListNode.cc
 *
 *        Version:  1.0
 *        Created:  03/06/11 16:58:27
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Marco Beierer (mk), marco.beierer@gmail.com
 *        Company:  Saxion Student
 *
 * =====================================================================================
 */

#include "ListNode.h"
#include <iostream>
#include <cassert>

ListNode::ListNode(const Area* area) {
    next = 0;
    this->area = area;
}

ListNode::~ListNode() {
    // do nothing;
    // area's are deleted on the fly
}

bool ListNode::merge(const Area* area) {
    assert(area != 0);

    if (next != 0) {
        bool area_beforeNext = area->getEnd() + 1 == next->getArea()->getBase();
        bool area_afterNext = next->getArea()->getEnd() + 1 == area->getBase();
        
        if (area_beforeNext || area_afterNext) {
            ListNode* next_old = next;
            const Area* next_oldArea = next_old->getArea();

            next = next->getNext();

            // de nieuwe area is in iedere geval groter dan het momenteel element, dus kan insert direct worden aangeroepen
            // controleer maar eerst of er een merge met de volgende elementen nodig is
            if (area_beforeNext) {
                insert(new Area(area->getBase(), area->getSize() + next_oldArea->getSize()), true);
            }
            else {
                insert(new Area(next_oldArea->getBase(), next_oldArea->getSize() + area->getSize()), true);
            }
        
            delete next_oldArea;
            next_oldArea = 0;

            delete next_old;
            next_old = 0;
            
            return true;
        }
        // anders ga recursief werden als het volgend element grooter is dan de area
        return next->merge(area);
    }
    return false;
}

void ListNode::insert(const Area* area, bool merge) {
    assert(area != 0);

    // controleer of er een volgend lijst element is
    if (next == 0) {
        next = new ListNode(area);
    }
    // delete old area if merge is successfull
    else if (merge && this->merge(area)) { // lazy evaluation van merge(area)
        delete area;
    }
    // controleer of de area groote kleiner dan de groote van het volgende element is
    else if (area->getSize() < next->getArea()->getSize()) {
        ListNode* node_new = new ListNode(area);
        node_new->setNext(next);
        next = node_new;
    }
    // ga recursief werden als het volgend element grooter is dan de area
    else {
        next->insert(area);
    }
}

const Area* ListNode::getBestFittedHole(int size) {
    assert(size > 0);

    // return 0 als er geen volgend element is
    if (next == 0) {
        return 0;
    }
    // als groote kleiner dan groote van het volgend element is dan verwijder het volgend element en return de area
    else if (size <= next->getArea()->getSize()) {
        const Area* area = next->getArea();
        ListNode* next_new = next->getNext();

        delete next;
        next = next_new;

        return area;
    }
    // ga recursief verder als het gezocht element nog niet gevonden is
    else {
        return next->getBestFittedHole(size);
    }
}

ListNode* ListNode::getNext() {
    return next;
}

const Area* ListNode::getArea() {
    return area;
}

void ListNode::setNext(ListNode* node) {
    assert(node != 0);
    next = node;
}

void ListNode::setArea(const Area* area) {
    assert(area != 0);
    this->area = area;
}

void ListNode::deleteNext() {
    if (next != 0) {
        next->deleteNext();
    }
    delete area;
    delete next;
}
